﻿//-----------------------------------------------------------------------
// <copyright file="EntityCreateData.cs" company="Nathan Miller">
// Copyright (c) Nathan Miller.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
//-----------------------------------------------------------------------
namespace TileTool.Scene.Entity
{
    using System;
    using TileTool.Common;
    using TileTool.Common.Math;
    using TileTool.DataBag;

    /// <summary>
    /// Creation data class passed to all entities during the creation process.
    /// </summary>
    public class EntityCreateData : CreateData
    {
        #region Fields - Private

        /// <summary>
        /// Data bag for the entity.
        /// </summary>
        private DataBag bag;

        /// <summary>
        /// Entity name.
        /// </summary>
        private DataBagValue<string> name;

        /// <summary>
        /// Matrix for the entity.
        /// </summary>
        private DataBagValue<Matrix2D> mat;

        /// <summary>
        /// Size of the entity.
        /// </summary>
        private DataBagValue<Size2D> size;

        /// <summary>
        /// Color of the entity.
        /// </summary>
        private DataBagValue<ColorRGBA> color;

        /// <summary>
        /// Entity GUID.
        /// </summary>
        private DataBagValue<string> guid;

        /// <summary>
        /// Parent GUID.
        /// </summary>
        private DataBagValue<string> parentGuid;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public EntityCreateData()
        {
            this.bag = new DataBag();

            this.SetupValues();
        }

        /// <summary>
        /// Construct the create data from a data bag.
        /// </summary>
        /// <param name="bag">Source data bag.</param>
        public EntityCreateData(IDataBag bag)
        {
            if (bag == null)
            {
                throw new ArgumentNullException("bag", "Bag must be non-null.");
            }

            this.bag = bag.Clone() as DataBag;
            if (this.bag == null)
            {
                this.bag = new DataBag();
            }

            this.SetupValues();
        }

        #endregion

        #region Properties - General

        /// <summary>
        /// Gets the data bag for the entity. Will be cloned on entity creation.
        /// </summary>
        public DataBag Bag
        {
            get
            {
                return this.bag;
            }
        }

        /// <summary>
        /// Gets or sets the entity's GUID.
        /// 
        /// If the GUID is Guid.Empty, the entity is expected to
        /// create a new GUID for itself.
        /// </summary>
        public Guid Guid
        {
            get
            {
                return new Guid(this.guid.Value);
            }

            set
            {
                this.guid.Value = value.ToString();
            }
        }

        /// <summary>
        /// Gets or sets the entity's parent GUID.
        /// 
        /// This field is ignored by entities during creation and
        /// is used by higher level systems.
        /// </summary>
        public Guid ParentGuid
        {
            get
            {
                return new Guid(this.parentGuid.Value);
            }

            set
            {
                this.parentGuid.Value = value.ToString();
            }
        }

        /// <summary>
        /// Gets if the parent GUID is valid.
        /// </summary>
        public bool ParentGuidValid
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets or sets the name of the entity.
        /// </summary>
        public string Name
        {
            get
            {
                return this.name.Value;
            }

            set
            {
                this.name.Value = value;
            }
        }

        /// <summary>
        /// Gets or sets the color of the entity.
        /// </summary>
        public ColorRGBA Color
        {
            get
            {
                return this.color.Value;
            }

            set
            {
                this.color.Value = value;
            }
        }

        #endregion

        #region Properties - Position / Orientation / Size

        /// <summary>
        /// Gets or sets the matrix for the entity.
        /// </summary>
        public Matrix2D Matrix
        {
            get
            {
                return this.mat.Value;
            }

            set
            {
                this.mat.Value = value;
            }
        }

        /// <summary>
        /// Gets or sets the size of the entity.
        /// </summary>
        public Size2D Size
        {
            get
            {
                return this.size.Value;
            }

            set
            {
                float w = MathUtility.Clamp(value.Width, EntityUtility.MinSize, EntityUtility.MaxSize);
                float h = MathUtility.Clamp(value.Height, EntityUtility.MinSize, EntityUtility.MaxSize);

                this.size.Value = new Size2D(w, h);
            }
        }

        #endregion

        #region Methods - Public

        /// <summary>
        /// Validate the creation data and ensure it is correct.
        /// </summary>
        public override void Validate()
        {
        }

        #endregion

        #region Methods - Private

        /// <summary>
        /// Setup all data bag values from create data.
        /// </summary>
        private void SetupValues()
        {
            this.name = this.bag.GetOrCreateValue<string>(EntityDataBagKeys.Name, string.Empty);
            this.mat = this.bag.GetOrCreateValue<Matrix2D>(EntityDataBagKeys.Matrix, Matrix2D.Identity);
            this.size = this.bag.GetOrCreateValue<Size2D>(EntityDataBagKeys.Size, new Size2D(EntityUtility.DefaultSize));
            this.color = this.bag.GetOrCreateValue<ColorRGBA>(EntityDataBagKeys.Color, ColorRGBA.White);
            this.guid = this.bag.GetOrCreateValue<string>(EntityDataBagKeys.Guid, Guid.Empty.ToString());
            this.parentGuid = this.bag.GetOrCreateValue<string>(EntityDataBagKeys.ParentGuid, Guid.Empty.ToString());

            this.ValidateGuids();
        }

        /// <summary>
        /// Validate the GUIDs we got from the databag to make sure that they are valid.
        /// </summary>
        private void ValidateGuids()
        {
            Guid temp;
            if (!Guid.TryParse(this.guid.Value, out temp))
            {
                this.guid.Value = Guid.Empty.ToString();
            }

            this.ParentGuidValid = true;
            if (!Guid.TryParse(this.parentGuid.Value, out temp))
            {
                this.parentGuid.Value = Guid.Empty.ToString();
                this.ParentGuidValid = false;
            }
        }

        #endregion
    }
}
